﻿/**************************************************************
*作者：Leon
*创建时间：2022/4/5 18:32:10
**************************************************************/
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

namespace Lad.DrawProject.Controls;

public class RubberbandAdorner : Adorner
{
    private Point? startPoint;
    private Point? endPoint;
    private readonly List<Point> pointList = new();

    private readonly Pen rubberbandPen;

    private readonly BaseCanvas _designerCanvas;

    private IBaseCanvasViewModel ViewModel
    {
        get
        {
            if (_designerCanvas.DataContext is IBaseCanvasViewModel viewModel)
                return viewModel;
            throw new NotImplementedException("DesignerCanvas.DataContext is not IDiagramViewModel的类型");
        }
    }
    private IDiagramServiceProvider Service { get { return DiagramServicesProvider.Instance; } }

    public RubberbandAdorner(BaseCanvas designerCanvas, Point? dragStartPoint)
        : base(designerCanvas)
    {
        this._designerCanvas = designerCanvas;
        this.startPoint = dragStartPoint;
        var scaleLevel = designerCanvas.RenderTransform.Value.M11;
        rubberbandPen = new(Brushes.LightSlateGray, 2/scaleLevel) { DashStyle = new DashStyle(new double[] { 2 }, 1) };
        
    }

    protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            if (!this.IsMouseCaptured)
                this.CaptureMouse();

            endPoint = e.GetPosition(this);
            if (this.Service.DrawMode == DrawMode.Polyline)
            {
                if (pointList.Count == 0 && this.startPoint.HasValue)
                {
                    pointList.Add(this.startPoint.Value);
                }
                pointList.Add(endPoint.Value);
            }

            UpdateSelection();
            this.InvalidateVisual();
        }
        else if (this.Service.DrawMode == DrawMode.DirectLine)
        {

        }
        else
        {
            if (this.IsMouseCaptured)
                this.ReleaseMouseCapture();
        }

        e.Handled = true;
    }

    protected override void OnMouseUp(System.Windows.Input.MouseButtonEventArgs e)
    {
        if (this.Service.DrawMode == DrawMode.DirectLine && e.ChangedButton == MouseButton.Left)
        {
            endPoint = e.GetPosition(this);

            bool isend = false;
            if (isend == false)
            {
                pointList.Add(endPoint.Value);


                UpdateSelection();
                this.InvalidateVisual();

                return;
            }
            else
            {
                this.Service.DrawMode=DrawMode.Polygon;
            }

        }

        // release mouse capture
        if (this.IsMouseCaptured)
            this.ReleaseMouseCapture();

        // remove this adorner from adorner layer
        AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this._designerCanvas);
        if (adornerLayer != null)
            adornerLayer.Remove(this);

        if (this.Service.DrawMode == DrawMode.Line ||
            this.Service.DrawMode == DrawMode.Rectangle ||
            this.Service.DrawMode == DrawMode.Ellipse ||
            this.Service.DrawMode == DrawMode.Polyline ||
            this.Service.DrawMode == DrawMode.Polygon ||
            this.Service.DrawMode == DrawMode.DirectLine ||
            this.Service.DrawMode == DrawMode.Text)
        {
            if (this.startPoint.HasValue && this.endPoint.HasValue)
            {
                if (this.Service.DrawMode == DrawMode.Polyline
                    || this.Service.DrawMode == DrawMode.Polygon
                    || this.Service.DrawMode == DrawMode.DirectLine)
                {

                }
                else if (this.Service.DrawMode == DrawMode.Text)
                {
                    TextDesignerItemViewModel itemBase = new ();
                    Point position = e.GetPosition(this);
                    itemBase.Left = Math.Min(this.startPoint.Value.X, this.endPoint.Value.X);
                    itemBase.Top = Math.Min(this.startPoint.Value.Y, this.endPoint.Value.Y);
                    itemBase.Width = Math.Abs(this.endPoint.Value.X - this.startPoint.Value.X);
                    itemBase.Height = Math.Abs(this.endPoint.Value.Y - this.startPoint.Value.Y);

                    ViewModel.AddItemCommand.Execute(itemBase);
                }
                else
                {

                }
            }
            this.Service.ResetDrawMode();
        }

        e.Handled = true;
    }

    protected override void OnRender(DrawingContext dc)
    {
        base.OnRender(dc);

        // without a background the OnMouseMove event would not be fired !
        // Alternative: implement a Canvas as a child of this adorner, like
        // the ConnectionAdorner does.
        dc.DrawRectangle(Brushes.Transparent, null, new Rect(RenderSize));

        if (this.startPoint.HasValue && this.endPoint.HasValue)
        {
            if (this.Service.DrawMode == DrawMode.Line)
            {
                dc.DrawLine(rubberbandPen, this.startPoint.Value, this.endPoint.Value);
            }
            else if (this.Service.DrawMode == DrawMode.Ellipse)
            {
                var centerPoint = new Point((this.startPoint.Value.X + this.endPoint.Value.X) / 2, (this.startPoint.Value.Y + this.endPoint.Value.Y) / 2);
                dc.DrawEllipse(Brushes.Transparent, rubberbandPen, centerPoint, Math.Abs(this.startPoint.Value.X - this.endPoint.Value.X) / 2, Math.Abs(this.startPoint.Value.Y - this.endPoint.Value.Y) / 2);
            }
            else if (Service.DrawMode == DrawMode.Polyline)
            {
                var disList = pointList.ToList();
                for (int i = 1; i < pointList.Count; i++)
                {
                    dc.DrawLine(rubberbandPen, disList[i - 1], disList[i]);
                }
            }
            else if (Service.DrawMode == DrawMode.DirectLine)
            {
                var disList = pointList.ToList();
                for (int i = 1; i < pointList.Count; i++)
                {
                    dc.DrawLine(rubberbandPen, disList[i - 1], disList[i]);
                }
            }
            else
            {
                dc.DrawRectangle(Brushes.Transparent, rubberbandPen, new Rect(this.startPoint.Value, this.endPoint.Value));
            }
        }
    }


    private T GetParent<T>(Type parentType, DependencyObject dependencyObject) where T : DependencyObject
    {
        DependencyObject parent = VisualTreeHelper.GetParent(dependencyObject);
        if (parent.GetType() == parentType)
            return (T)parent;

        return GetParent<T>(parentType, parent);
    }


    /// <summary>
    /// 更新选择
    /// </summary>
    private void UpdateSelection()
    {
        IBaseCanvasViewModel vm = ViewModel;
        Rect rubberBand = new(startPoint ??= new(), endPoint ??= new());
        ItemsControl itemsControl = GetParent<ItemsControl>(typeof(ItemsControl), _designerCanvas);

        foreach (SelectableItemViewModelBase item in vm.Items)
        {
            if (item is not null)
            {
                DependencyObject container = itemsControl.ItemContainerGenerator.ContainerFromItem(item);

                Rect itemRect = VisualTreeHelper.GetDescendantBounds((Visual)container);
                Rect itemBounds = ((Visual)container).TransformToAncestor(_designerCanvas).TransformBounds(itemRect);

                if (rubberBand.Contains(itemBounds))
                {
                    //item.IsSelected = true;
                    vm.SelectionService.AddToSelection(item);
                }
                else
                {
                    if (!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
                    {
                        //item.IsSelected = false;
                        vm.SelectionService.RemoveFromSelection(item);
                    }
                }
            }
        }
    }
}
